package gui.inventory;

import gui.common.*;
import gui.item.*;
import gui.product.*;

import java.util.*;

import com.sun.jdi.connect.Connector.SelectedArgument;

import core.*;

/**
 * Controller class for inventory view.
 */

@SuppressWarnings("unused") public class InventoryController extends Controller 
									implements IInventoryController, Observer {

	/**
	 * pointer to the core model
	 */
	CoreFacade core;
	
	private List<ItemData> items;
	private List<ProductData> prods;
	private boolean productUpdateFlag;
	/**
	 * Constructor.
	 *  
	 * @param view Reference to the inventory view
	 */
	public InventoryController(IInventoryView view) {
		super(view);
		items = new ArrayList<ItemData>();
		prods = new ArrayList<ProductData>();
		productUpdateFlag = false;
		core = CoreFacade.getInstance();
		core.addObserver(this);
		boolean load = false;
		/*try {
			//core.loadDataFromMemory();
			core.loadDataFromMemory()
			load = true;
		} 
		catch (Exception e) {
			System.out.println("Files Not Found! \n");
		}*/
		
		//Load Temp Data into Model
		// Remove this after testing
		construct();
		//initializeTempModel();
		
		
	}

	/**
	 * Returns a reference to the view for this controller.
	 */
	@Override
	protected IInventoryView getView() {
		return (IInventoryView)super.getView();
	}

	private ProductContainerData root;
	/**
	 * Loads data into the controller's view.
	 * 
	 *  {@pre None}
	 *  
	 *  {@post The controller has loaded data into its view}
	 */
	@Override
	protected void loadValues() {
		
		root = new ProductContainerData();
		root.setName("root");
		List<StorageUnit> storageUnits = core.getStorageUnits();
		Collections.sort(storageUnits);
		for(StorageUnit s : storageUnits)
		{
			ProductContainerData temp = new ProductContainerData(s.getName());
			temp.setTag(s);
			temp.setParent(root);
			RecursivelyAddChildren(s, temp);
			root.addChild(temp);
		}
		
		getView().setProductContainers(root);
		
		/*
		ProductContainerData basementCloset = new ProductContainerData("Basement Closet");
		
		ProductContainerData toothpaste = new ProductContainerData("Toothpaste");
		toothpaste.addChild(new ProductContainerData("Kids"));
		toothpaste.addChild(new ProductContainerData("Parents"));
		basementCloset.addChild(toothpaste);
		
		root.addChild(basementCloset);
		
		ProductContainerData foodStorage = new ProductContainerData("Food Storage Room");
		
		ProductContainerData soup = new ProductContainerData("Soup");
		soup.addChild(new ProductContainerData("Chicken Noodle"));
		soup.addChild(new ProductContainerData("Split Pea"));
		soup.addChild(new ProductContainerData("Tomato"));
		foodStorage.addChild(soup);
		root.addChild(foodStorage);
		getView().setProductContainers(root);
		*/
		
		
	}
	
	private void RecursivelyAddChildren(ProductContainer s, ProductContainerData pc)
	{
		List<ProductGroup> pgs = s.getProductGroups();
		Collections.sort(pgs);
		for(ProductGroup pg : pgs)
		{
			ProductContainerData child = new ProductContainerData(pg.getName());
			child.setTag(pg);
			child.setParent(pc);
			RecursivelyAddChildren(pg, child);
			pc.addChild(child);
		}
		
	}
	

	/**
	 * Sets the enable/disable state of all components in the controller's view.
	 * A component should be enabled only if the user is currently
	 * allowed to interact with that component.
	 * 
	 * {@pre None}
	 * 
	 * {@post The enable/disable state of all components in the controller's view
	 * have been set appropriately.}
	 */
	@Override
	protected void enableComponents() {

		core.LoadDatabase();
		return;
	}
	
	//
	// IInventoryController overrides
	//

	/**
	 * Returns true if and only if the "Add Storage Unit" menu item should be enabled.
	 */
	@Override
	public boolean canAddStorageUnit() {
		// This should always be enabled
		return true;
	}
	
	/**
	 * Returns true if and only if the "Add Items" menu item should be enabled.
	 */
	@Override
	public boolean canAddItems() {
		return true;
	}
	
	/**
	 * Returns true if and only if the "Transfer Items" menu item should be enabled.
	 */
	@Override
	public boolean canTransferItems() {
		return true;
	}
	
	/**
	 * Returns true if and only if the "Remove Items" menu item should be enabled.
	 */
	@Override
	public boolean canRemoveItems() {
		return true;
	}

	/**
	 * Returns true if and only if the "Delete Storage Unit" menu item should be enabled.
	 */
	@Override
	public boolean canDeleteStorageUnit() {
		ProductContainerData productContainerData = getView().getSelectedProductContainer();
		if(productContainerData != null)
		{	
			StorageUnit su = (StorageUnit)productContainerData.getTag();
			System.out.println("Checking if canDeleteStorageUnit:" + su.getName());
			return core.canDeleteStorageUnit(su);
		}
		return true;
	}
	
	/**
	 * This method is called when the user selects the "Delete Storage Unit" menu item.
	 */
	@Override
	public void deleteStorageUnit() {
		ProductContainerData temp = getView().getSelectedProductContainer();
		
		
		StorageUnit su = (StorageUnit)temp.getTag();
		
		
		
		if(!core.deleteStorageUnit(su))
			getView().displayWarningMessage("Deleting Storage Unit Failed!!");
		else
		{
//			getView().selectProductContainer(new ProductContainerData());
			getView().deleteProductContainer(temp);
			getView().setContextGroup("");
			getView().setContextSupply("");
			getView().setContextUnit("");
			loadValues();
			
//			core.deleteSubGroups(su);
		}
			
	}

	/**
	 * Returns true if and only if the "Edit Storage Unit" menu item should be enabled.
	 */
	@Override
	public boolean canEditStorageUnit() {
		return true;
	}

	/**
	 * Returns true if and only if the "Add Product Group" menu item should be enabled.
	 */
	@Override
	public boolean canAddProductGroup() {
		return true;
	}

	/**
	 * Returns true if and only if the "Delete Product Group" menu item should be enabled.
	 */
	@Override
	public boolean canDeleteProductGroup() { 
		ProductGroup pg = (ProductGroup)getView().getSelectedProductContainer().getTag();
		return core.canDeleteProductGroup(pg, pg.getParentContainer());
	}

	/**
	 * Returns true if and only if the "Edit Product Group" menu item should be enabled.
	 */
	@Override
	public boolean canEditProductGroup() {
		return true;
	}
	
	/**
	 * This method is called when the user selects the "Delete Product Group" menu item.
	 */
	@Override
	public void deleteProductGroup() {
		ProductContainerData data = getView().getSelectedProductContainer();
		ProductGroup pg = (ProductGroup)data.getTag();
		if(!core.deleteProductGroup(pg,pg.getParentContainer()))
			getView().displayWarningMessage("Deleting ProductGroup Failed!!");
		else
		{
			getView().deleteProductContainer(data);
			//getView().selectProductContainer(data.getParent());
			//loadValues();
			productContainerSelectionChanged();
			getView().setContextUnit("");
			getView().setContextGroup("");
			getView().setContextSupply("");
		}
	}
	
//	private Random rand = new Random();
//	
//	private String getRandomBarcode() {
//		Random rand = new Random();
//		StringBuilder barcode = new StringBuilder();
//		for (int i = 0; i < 12; ++i) {
//			barcode.append(((Integer)rand.nextInt(10)).toString());
//		}
//		return barcode.toString();
//	}

	/**
	 * This method is called when the selected item container changes.
	 */
	@Override
	public void productContainerSelectionChanged() 
	{
		List<ProductData> productDataList = new ArrayList<ProductData>();
		
		ProductContainerData selectedContainer = getView().getSelectedProductContainer();
		
		if(selectedContainer != null)
		{
			if(isRoot(selectedContainer))
			{
				// root is selected, display all products and items
				getView().setContextUnit("All");
				getView().setContextGroup("");
				getView().setContextSupply("");
				displayRootContainerProducts(selectedContainer);
				return;
			}
			ProductContainer actualContainer;
			if(selectedContainer.getTag() instanceof StorageUnit)
			{
				actualContainer = (StorageUnit)selectedContainer.getTag();
				getView().setContextUnit(actualContainer.getName());
				getView().setContextGroup("");
				getView().setContextSupply("");
			}
			else
			{
				actualContainer = (ProductGroup)selectedContainer.getTag();
				ProductGroup group = (ProductGroup) actualContainer;
				StorageUnit su = core.getParentStorageUnit(actualContainer);
				getView().setContextUnit(su.getName());
				getView().setContextGroup(actualContainer.getName());
				getView().setContextSupply(group.getThreeMonthSupplyAmount().toString());
				if(group.getThreeMonthSupplyAmount().getSize() == 0)
				{
					getView().setContextSupply("");
				}
			}
			Set<Product> products = core.getAllProducts(actualContainer);
//			System.out.println("Amount of products found:" + products.size() +
//					" in " + actualContainer.getName());
			Iterator<Product> iter = products.iterator();
			List<Product> prods = new ArrayList<Product>(products);
			
			Collections.sort(prods);
			for(int i = 0; i < prods.size(); i++)
			{
				Product temp = prods.get(i);
				ProductData productData = convertToProductData(temp,
						core.getCountOfProdInProductContainer(temp, actualContainer));
				//productData.setBarcode(temp.getBarcodeString());
				//new ProductData();			
				/*productData.setBarcode(temp.getBarCode().getBarcode());
				int count = core.getCountOfProdInProductContainer(temp, actualContainer);
				productData.setCount(Integer.toString(count));
				
				productData.setDescription(temp.getDescription());
				
				productData.setShelfLife(Integer.toString(temp.getShelfLife()) + " months");
				productData.setSize(temp.getAmount().toString());
				productData.setSupply(Integer.toString(temp.getThreeMonthSupply()) + " count");
				productData.setTag(temp);*/
				
				productDataList.add(productData);
				
			}
		}
		this.prods = new ArrayList<ProductData>(productDataList);
		
		getView().setProducts(this.prods.toArray(new ProductData[0]));
		
		if(productUpdateFlag)
		{
			productUpdateFlag = false;
		}
		else
			getView().setItems(new ItemData[0]);
	
	}
	
	private void displayRootContainerProducts(ProductContainerData root)
	{
		List<ProductData> productDataList = new ArrayList<ProductData>();
		
		List<Product> prods = core.getAllProductInRoot();
		Set<Item> items = (Set<Item>)core.getAllItemsInRoot();
		
		
		Map<Product, Integer> prodCount = new HashMap<Product, Integer>();
		Iterator<Item> iter = items.iterator();
		while(iter.hasNext())
		{
			Item i = iter.next();
			
			if(!prodCount.containsKey(i.getProduct()))
			{
				prodCount.put(i.getProduct(), 1);
			}
			else
				prodCount.put(i.getProduct(), prodCount.get(i.getProduct()) + 1);
		}

		Collections.sort(prods);
		for(Product p : prods)
		{
			
			ProductData productData = new ProductData();			
			productData.setBarcode(p.getBarcodeString());

			int count;
			if(prodCount.containsKey(p))
				count = prodCount.get(p);
			else
				count = 0;
			productData.setCount(Integer.toString(count));
			
			productData.setDescription(p.getDescription());
			
			productData.setShelfLife(Integer.toString(p.getShelfLife()) + " months");
			productData.setSize(p.getAmount().toString());
			productData.setSupply(Integer.toString(p.getThreeMonthSupply()) + " count");
			productData.setTag(p);
			
			productDataList.add(productData);
		}
		
		getView().setProducts(productDataList.toArray(new ProductData[0]));
		
		this.prods = new ArrayList<ProductData>(productDataList);
		if(productUpdateFlag)
		{
			productUpdateFlag = false;
		}
		else
			getView().setItems(new ItemData[0]);
	}

	/**
	 * This method is called when the selected item changes.
	 */
	@Override
	public void productSelectionChanged() 
	{
		List<ItemData> itemDataList = new ArrayList<ItemData>();		
		ProductData selectedProduct = getView().getSelectedProduct();
		if(selectedProduct == null)
			return;
		Product p = (Product)selectedProduct.getTag();
		if (selectedProduct != null) 
		{
			ProductContainerData selectedContainer = getView().getSelectedProductContainer();
			if(isRoot(selectedContainer))
			{
				// then we are displaying root storage unit's items
				displayRootContainerItems(p);
				return;
			}
			ProductContainer pc = (ProductContainer)selectedContainer.getTag();
			StorageUnit su;
			try
			{
				su = core.getParentStorageUnit(pc);
			} catch (Exception e)
			{
				getView().displayWarningMessage(e.getMessage());
				e.printStackTrace();
				return;
			}
			Set<Item> items = core.getAllItems(pc);
			Iterator<Item> iter = items.iterator();
			List<Item> itms = new ArrayList<Item>(items);
			Collections.sort(itms);
			for(int i = 0; i < itms.size(); i++)
			{
				Item temp = itms.get(i);
				if(temp.getProduct().equals(p))
				{
					ItemData itemData = convertToItemData(temp);//new ItemData();
					/*itemData.setBarcode(temp.getBarcode().getBarcode());
					itemData.setEntryDate(temp.getEntryDate().getTime());
					if (temp.getExpirationDate() != null)
					{
						itemData.setExpirationDate(temp.getExpirationDate().getTime());
					}
					else
					{
						itemData.setExpirationDate(null);
					}
					if(pc instanceof StorageUnit)
						itemData.setProductGroup("");
					else
						itemData.setProductGroup(pc.getName());
					itemData.setStorageUnit(su.getName());
					itemData.setTag(temp);*/
					itemDataList.add(itemData);
				}
			}
		}
		items = new ArrayList<ItemData>(itemDataList);
		getView().setItems(items.toArray(new ItemData[0]));
		
	}
	
	private void displayRootContainerItems(Product p)
	{
		List<ItemData> itemDataList = new ArrayList<ItemData>();
		Set<Item> items = (Set<Item>) core.getAllItemsInRoot();
		List<Item> itms = new ArrayList<Item>(items);
		Collections.sort(itms);
		
		Iterator<Item> iter = items.iterator();
		for(int index = 0; index < itms.size();index++)
		{
			Item i = itms.get(index);
			ProductContainer pc = i.getProductContainer();
			StorageUnit su = core.getParentStorageUnit(pc);
			if(i.getProduct().equals(p))
			{
				ItemData itemData = new ItemData();
				itemData.setBarcode(i.getBarcodeString());
				itemData.setEntryDate(i.getEntryDate().getTime());
				if (i.getExpirationDate() != null)
				{
					itemData.setExpirationDate(i.getExpirationDate().getTime());
				}
				else
				{
					itemData.setExpirationDate(null);
				}
				
				if(pc instanceof StorageUnit)
					itemData.setProductGroup("");
				else
					itemData.setProductGroup(pc.getName());
				itemData.setStorageUnit(su.getName());
				itemData.setTag(i);
				itemDataList.add(itemData);
			}
		}
		this.items = new ArrayList<ItemData>(itemDataList);
		
		getView().setItems(itemDataList.toArray(new ItemData[0]));
	}
	
	/**
	 * This method is called when any of the fields in the
	 * add item batch view have been changed by the user.
	 */
	@Override
	public void valuesChanged()
	{
		
	}

	/**
	 * This method is called when the selected item changes.
	 */
	@Override
	public void itemSelectionChanged() {
		return;
	}

	/**
	 * Returns true if and only if the "Delete Product" menu item should be enabled.
	 */
	@Override
	public boolean canDeleteProduct() {
		ProductData prodData = getView().getSelectedProduct();
		if(prodData != null)
		{
			Product prod = (Product)getView().getSelectedProduct().getTag();
			ProductContainerData selectedContainer = getView().getSelectedProductContainer();
			if(isRoot(selectedContainer))
			{
				return core.canDeleteProduct(prod);
			}
			ProductContainer pc = (ProductContainer)selectedContainer.getTag();
			return core.canDeleteProductFromContainer(prod,pc);
		}
		else
			return false;
	}

	
	/**
	 * This method is called when the user selects the "Delete Product" menu item.
	 */
	@Override
	public void deleteProduct()
	{
		ProductContainerData selectedContainer = getView().getSelectedProductContainer();
		Product prod = (Product)getView().getSelectedProduct().getTag();
		if(isRoot(selectedContainer))
		{
			// this branch of code needs to call coreFacade to remove product from entire system
			try
			{
				core.deleteProduct(prod);
				productContainerSelectionChanged();
				return;
			} catch (Exception e)
			{
				getView().displayWarningMessage("deleting Product " 
						+ prod.getDescription() + " from system failed");
				e.printStackTrace();
			}
			
		}
		
		ProductContainer pc = (ProductContainer)getView().getSelectedProductContainer().getTag();
		if(core.canDeleteProductFromContainer(prod,pc))
		{
			boolean result = core.deleteProductFromContainer(prod, pc);
			productContainerSelectionChanged();
				
		}
		
	}

	/**
	 * Returns true if and only if the "Edit Item" menu item should be enabled.
	 */
	@Override
	public boolean canEditItem() {
        if(getView().getSelectedItem() == null)
        {
            return false;
        }
		return true;
	}

	/**
	 * This method is called when the user selects the "Edit Item" menu item.
	 */
	@Override
	public void editItem() {
		getView().displayEditItemView();
	}

	/**
	 * Returns true if and only if the "Remove Item" menu item should be enabled.
	 */
	@Override
	public boolean canRemoveItem() {
		if(getView().getSelectedItem() == null)
        {
            return false;
        }
		return true;
	}

	/**
	 * This method is called when the user selects the "Remove Item" menu item.
	 */
	@Override
	public void removeItem() {
		ItemData itemData = getView().getSelectedItem();
		if(itemData == null)
			return;
		Item item = (Item)itemData.getTag();
		try
		{
			if(core.removeItem(item)==null)
				getView().displayWarningMessage("removing item " 
						+ item.getBarcodeString() +" was unsuccessful");
		} catch (Exception e)
		{
			getView().displayWarningMessage("removing item "+ item.getBarcodeString() +
					" failed");
			e.printStackTrace();
		}
		ProductData selectedProduct = getView().getSelectedProduct();
		Product p = (Product) selectedProduct.getTag();
		String pBarcode = p.getBarcodeString();
		productContainerSelectionChanged();
		for(int i = 0; i < prods.size(); i++)
		{
			if(prods.get(i).getBarcode().equals(pBarcode))
			{
				getView().selectProduct(prods.get(i));
			}
		}
		
		productSelectionChanged();
	}

	/**
	 * Returns true if and only if the "Edit Product" menu item should be enabled.
	 */
	@Override
	public boolean canEditProduct() {
		if(getView().getSelectedProduct()==null)
			return false;
		return true;
	}

	/**
	 * This method is called when the user selects the "Add Product Group" menu item.
	 */
	@Override
	public void addProductGroup() {
		getView().displayAddProductGroupView();
		
//		loadValues();
	}
	
	/**
	 * This method is called when the user selects the "Add Items" menu item.
	 */
	@Override
	public void addItems() {
		getView().displayAddItemBatchView();
	}
	
	/**
	 * This method is called when the user selects the "Transfer Items" menu item.
	 */
	@Override
	public void transferItems() {
		getView().displayTransferItemBatchView();
		productContainerSelectionChanged();
	}
	
	/**
	 * This method is called when the user selects the "Remove Items" menu item.
	 */
	@Override
	public void removeItems() {
		getView().displayRemoveItemBatchView();
		productContainerSelectionChanged();
	}

	/**
	 * This method is called when the user selects the "Add Storage Unit" menu item.
	 */
	@Override
	public void addStorageUnit() {
		getView().displayAddStorageUnitView();
		//loadValues();
	}

	/**
	 * This method is called when the user selects the "Edit Product Group" menu item.
	 */
	@Override
	public void editProductGroup() {
		getView().displayEditProductGroupView();
		ProductContainerData thisOne = getView().getSelectedProductContainer();
	}

	/**
	 * This method is called when the user selects the "Edit Storage Unit" menu item.
	 */
	@Override
	public void editStorageUnit() {
		getView().displayEditStorageUnitView();
		ProductContainerData thisOne = getView().getSelectedProductContainer();
		/*
		for(int i = 0; i < root.getChildCount(); i++)
		{
			if(root.getChild(i).getName().equals(thisOne.getName()))
			{
				//getView().insertProductContainer(root, thisOne, i);
				break;
			}
		}
		*/
		//loadValues();
	}

	/**
	 * This method is called when the user selects the "Edit Product" menu item.
	 */
	@Override
	public void editProduct() {
		getView().displayEditProductView();
		//productContainerSelectionChanged();
	}
	
	/**
	 * This method is called when the user drags a product into a
	 * product container.
	 * 
	 * @param productData Product dragged into the target product container
	 * @param containerData Target product container
	 */
	@Override
	public void addProductToContainer(ProductData productData, 
										ProductContainerData containerData) 
	{	
		ProductContainerData fromContainer = getView().getSelectedProductContainer();
		if(isRoot(fromContainer))
		{
			try{
				ProductContainer pc = (ProductContainer) containerData.getTag();
				Product p = (Product) productData.getTag();
				core.transferProductToContainer(p, pc);
				return;
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
			
		}
		Product prod = (Product)productData.getTag();
		ProductContainer targetPC = (ProductContainer)containerData.getTag();
		ProductContainer fromPC = 
				(ProductContainer)getView().getSelectedProductContainer().getTag();
		try
		{
			// may need to add check here, because this may 
			//not be a transfer, but just a regular add
			core.transferProduct(prod, fromPC, targetPC);
		} catch (Exception e)
		{
			getView().displayWarningMessage("Error transferring Product: " 
					+prod.getDescription() + " from " + fromPC.getName() + " to " 
					+ targetPC.getName() + e.getMessage());
			e.printStackTrace();
		}
		productContainerSelectionChanged();
	}

	/**
	 * This method is called when the user drags an item into
	 * a product container.
	 * 
	 * @param itemData Item dragged into the target product container
	 * @param containerData Target product container
	 */
	@Override
	public void moveItemToContainer(ItemData itemData,
									ProductContainerData containerData) 
	{
		Item item = (Item) itemData.getTag();
		ProductContainer targetPC = (ProductContainer) containerData.getTag();
		StorageUnit su = core.getParentStorageUnit(targetPC);
		
		try
		{
			core.transferItem(item, targetPC, su);
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		productContainerSelectionChanged();
		productSelectionChanged();
		
		
	}
	
	/**
	 * update is called when the class this controller is observing has sent
	 * a signal indicating a need to update data
	 */
	private void updateProductGroup(Observable subject, Object hint)
	{
			ProductGroup pg = (ProductGroup) hint;
			ProductContainerData newUnit = new ProductContainerData();
			newUnit.setName(pg.getName());
			newUnit.setTag(hint);
			if(pg.getUpdateFlag())
			{
				ProductContainerData selectedContainer = getView().getSelectedProductContainer();
				pg.setUpdateFlag(false);
				ProductContainerData parent = selectedContainer.getParent();
				getView().setContextGroup(pg.getName());
				if(pg.getThreeMonthSupplyAmount().getSize() != 0)
					getView().setContextSupply(pg.getThreeMonthSupplyAmount().toString());
				else
					getView().setContextSupply("");
				for(int i = 0; i < parent.getChildCount(); i++)
				{
					if(selectedContainer.getName().equals(parent.getChild(i).getName()))
					{
						getView().renameProductContainer
						          (selectedContainer, pg.getName(), 
								   getRenameIndex(selectedContainer, pg.getName()));
						getView().selectProductContainer(selectedContainer);
						ProductData prod = getView().getSelectedProduct();
						productContainerSelectionChanged();
						getView().selectProduct(prod);
						productSelectionChanged();
						break;
					}
				}
			}
			else if(pg.isRemoved())
			{
				
			}
			else
			{
				ProductContainerData parent = getView().getSelectedProductContainer();
				newUnit.setParent(parent);
				insertContainer(newUnit);
				productContainerSelectionChanged();
				productSelectionChanged();
			}
			productSelectionChanged();
		//	getView().selectProductContainer(newUnit);
			//loadValues();
	}
	
	private void updateStorageUnit(Observable subject, Object hint)
	{
		StorageUnit su = (StorageUnit) hint;
		ProductContainerData newUnit = new ProductContainerData();
		newUnit.setName(su.getName());
		newUnit.setTag(hint);
		if(su.getUpdateFlag())
		{
			su.setUpdateFlag(false);
			ProductContainerData selectedContainer = getView().getSelectedProductContainer();
			ProductContainerData parent = selectedContainer.getParent();
			for(int i = 0; i < parent.getChildCount(); i++)
			{
				if(parent.getChild(i).getName().equals(selectedContainer.getName()))
				{
					
					getView().renameProductContainer
				             (selectedContainer, su.getName(), 
				    		  getRenameIndex(selectedContainer, su.getName()));
					//getView().deleteProductContainer(selectedContainer);
					//insertContainer(selectedContainer);
					getView().selectProductContainer(selectedContainer);
					selectedContainer.setTag(su);
					ProductData prod = getView().getSelectedProduct();
					productContainerSelectionChanged();
//					getView().selectProduct(prod);
					productSelectionChanged();
					break;
				}
			}
		}
		else
		{
//			getView().insertProductContainer(root, newUnit, root.getChildCount());
			newUnit.setParent(root);
			insertContainer(newUnit);
			productContainerSelectionChanged();
			productSelectionChanged();
		}
		productSelectionChanged();
//		sortStorageUnits();
		//loadValues();
	}
	
	private void updateProduct(Observable subject, Object hint)
	{
		ProductData prod = getView().getSelectedProduct();
		if(prod !=null)
		{
			Product p = (Product) prod.getTag();
			if(p.isUpdated())
			{
				p.setUpdated(false);
				productUpdateFlag = true;
				productContainerSelectionChanged();
				for(int i = 0; i < prods.size(); i++)
				{
					ProductData temp = prods.get(i);
					if(temp.getBarcode().equals(prod.getBarcode()))
					{
						getView().selectProduct(temp);
					}
				}
			}
			else
			{
				productContainerSelectionChanged();
			}
		}
	}
	
	private void updateItem(Observable subject, Object hint)
	{
			Item itemHint = (Item) hint;
			ProductData prod = getView().getSelectedProduct();
			ItemData selectedItem = getView().getSelectedItem();
			if(selectedItem != null)
				System.out.println("Selected Item = " +selectedItem.getBarcode());
			
			if(itemHint.isUpdated())
			{
				itemHint.setUpdated(false);
				productSelectionChanged();
				// This will reselect the updated item
				for(int i = 0; i < items.size();i++)
				{
					if(items.get(i).getBarcode().equals(selectedItem.getBarcode()))
					{
						getView().selectItem(items.get(i));
					}
				}
			}
			else
			{
				// adding a new item
				if(prod != null)
				{
					// in this case we need to update item list
					if(selectedItem != null)
					{
						// there was an item selected, need to keep this item selected
						Item it = (Item) selectedItem.getTag();
						Product p = it.getProduct();
						String pBarcode = p.getBarcodeString();
						productContainerSelectionChanged();
						for(int i = 0; i < prods.size(); i++)
						{
							ProductData temp = prods.get(i);
							if(temp.getBarcode().equals(pBarcode))
							{
								getView().selectProduct(temp);
							}
						}
						
						productSelectionChanged();
						for(int i = 0; i < items.size(); i++)
						{
							ItemData temp = items.get(i);
							String iBarcode = it.getBarcodeString();
							if(temp.getBarcode().equals(iBarcode))
							{
								getView().selectItem(temp);
							}
						}
					}
					else
					{
						productContainerSelectionChanged();
						//redisplayProducts(itemHint.getProduct().getBarcodeString());
					}
				}
				else
				{
					// product was null, don't update need items
					productContainerSelectionChanged();
				}
			}
	}
	
	@Override
	public void update(Observable subject, Object hint)
	{
		// since we are only observing CoreFacade, subject will always be CoreFacade
		if(hint instanceof Item)
		{
			updateItem(subject, hint);
		}
		else if(hint instanceof Product)
		{
			updateProduct(subject,hint);
			productSelectionChanged();
		}
		else if(hint instanceof String)
		{
			String s = (String)hint;
			getView().displayWarningMessage(s);
		}
		else if(hint instanceof StorageUnit)
		{
			updateStorageUnit(subject, hint);
		}
		else if(hint instanceof ProductGroup)
		{
			updateProductGroup(subject, hint);
		}
		else
			loadValues();
	}
	
	private void redisplayProducts(String prod)
	{
		if( !prod.isEmpty())
		{
			for(int i = 0; i < prods.size(); i++)
			{
				ProductData curProd = prods.get(i);
				if(curProd.getBarcode().equals(prod))
				{
					int newCount = Integer.parseInt(curProd.getCount()) +1;
					curProd.setCount(Integer.toString(newCount));
				}
			}
		}
		// keep currently selected Product selected
		ProductData curProd = getView().getSelectedProduct();
		if(curProd != null)
		{
			// display items too
			getView().setProducts(this.prods.toArray(new ProductData[0]));
			getView().selectProduct(curProd);
		}
		else
		{
			getView().setProducts(this.prods.toArray(new ProductData[0]));
		}
	}
	
	private boolean isRoot(ProductContainerData root)
	{
		if(root == null)
			return false;
		return (root.getName().equals("root") && root.getTag() == null);
	}
		
	private void insertContainer(ProductContainerData data)
	{
		ProductContainerData parent = data.getParent();
//		System.out.println("Checking where to insert ProductContainer");
		for(int i = 0; i < parent.getChildCount(); i++)
		{
			if(parent.getChild(i).compareTo(data) > 0 )
			{
				// this index is too far
//				System.out.println("Inserting " + data.getName() + " at pos:" + i);
				getView().insertProductContainer(parent, data, i);
				getView().selectProductContainer(data);
				return;
			}
		}
//		System.out.println("Inserting " + data.getName() + " at pos:" + parent.getChildCount());
		getView().insertProductContainer(parent, data, parent.getChildCount());
		getView().selectProductContainer(data);
	}
	
	private int getRenameIndex(ProductContainerData data, String newName)
	{
		ProductContainerData parent = data.getParent();
		boolean found = false;
//		System.out.println("Checking where to insert renamed ProductContainer");
		for(int i = 0; i < parent.getChildCount(); i++)
		{
			if(parent.getChild(i).getName().equals(data.getName()))
			{
				// we found the old position
				found = true;
			}
			if(parent.getChild(i).getName().compareTo(newName) > 0)
			{
				// this index is too far
				if(found)
					i--;
				if(i < 0)
					i = 0;
//				System.out.println("Index for rename " + newName + " at pos:" + i);
				return i;
			}
		}
//		System.out.println("Index for rename " + newName + " at pos:" + 
//				           (parent.getChildCount() - 1));
		return parent.getChildCount() - 1;
	}

}

